﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using AviFile;
using System.IO;
using Infragistics.Win.UltraWinEditors;

namespace ResponseMonitor
{
    public partial class RetrivalProcessForm : Form
    {
        //  外面传来的数据
        public string MonitorFile = string.Empty;
        public string RetrivalDir = string.Empty;
        public string ProjectDir = string.Empty;

        //  内部使用数据
        private int _videoFrameCount = 0;       //  视频文件的总帧数
        private double _videoFrameRate = 0;     //  视频文件每秒的帧数
        private int _millionSecondPerFrame = 0; //  视频文件每两帧间隔的毫秒数
        private List<int> _errorStimList = new List<int>();  //  记录有问题的stim

        List<RetrivalData> _retrivalDataList = new List<RetrivalData>();

        public RetrivalProcessForm()
        {
            InitializeComponent();
        }

        private void RetrivalProcessForm_Load(object sender, EventArgs e)
        {
            //  读取视频文件信息
            ReadVideoInfo();

            //  计算一些内部需要的数值
            CalculateData();

            //  生成Retrival数据
            if (!GenerateRetrivalData())
                return;

            //  数据生成完毕, 准备展现数据
            ShowRetrivalData();
        }

        private void ShowRetrivalData()
        {
            foreach (RetrivalData rd in _retrivalDataList)
            {
                panelContainer.Controls.Add(rd.LabelNo);
                foreach (UltraPictureBox pb in rd.imageList)
                    panelContainer.Controls.Add(pb);
                foreach (Button b in rd.buttonList)
                    panelContainer.Controls.Add(b);
            }

            //  恢复控件的显示
            labelMessage.Visible = false;
            panelContainer.Visible = true;
            ultraButtonOK.Visible = true;
        }

        private bool GenerateRetrivalData()
        {
            //  读取原方案中的各刺激时间点
            string testCaseFile = ProjectDir + @"\" + "TestCase.msc";
            string testCaseContent = string.Empty;
            try
            {
                using (StreamReader sr = new StreamReader(testCaseFile, Encoding.Default))
                {
                    testCaseContent = sr.ReadToEnd();
                }
            }
            catch (Exception ex)
            {
                // todo: 记录错误日志
                labelMessage.Text = "There is no TestCase file. Please close this window and select another project.";
                return false;
            }
            string[] lines = testCaseContent.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 1; i < lines.Length; i++)
            {
                int timespot = int.Parse(lines[i].Split(':')[0]);
                int frameNo = timespot / _millionSecondPerFrame + 1;

                RetrivalData rd = new RetrivalData();
                rd.StimNo = i;
                rd.TestCaseTimeSpot = timespot;
                rd.VideoFileFrameNo = frameNo;

                _retrivalDataList.Add(rd);
            }

            //
            _generateControls();

            return true;
        }

        private void _generateControls()
        {
            int s = 0;
            foreach (RetrivalData rd in _retrivalDataList)
            {
                s++;
                //  Label
                string labelText = "Stim " + s.ToString();
                string labelName = "labelMessage" + s.ToString();
                int labelY = (s - 1) * 350;
                rd.LabelNo.Font = new System.Drawing.Font("Tahoma", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                rd.LabelNo.ForeColor = System.Drawing.Color.White;
                rd.LabelNo.Location = new System.Drawing.Point(20, labelY);
                rd.LabelNo.Name = labelName;
                rd.LabelNo.Size = new System.Drawing.Size(200, 20);
                rd.LabelNo.Text = labelText;
                rd.LabelNo.TextAlign = System.Drawing.ContentAlignment.TopLeft;

                //  todo: PictureBox
                //  Generate images from avi file
                AviManager aviManager = new AviManager(MonitorFile, true);
                VideoStream stream = aviManager.GetVideoStream();
                stream.GetFrameOpen();
                int i;
                for (i = 0; i < 50; i++)
                {
                    int fn = rd.VideoFileFrameNo + i;
                    string fp = string.Format("{0}\\stim{1}_{2}.bmp", RetrivalDir, s, i);
                    if (fn >= _videoFrameCount)
                        break;
                    stream.ExportBitmap(fn, fp);
                }
                stream.GetFrameClose();
                aviManager.Close();
                //  Generate image controls
                for (int j = 0; j < i; j++)
                {
                    string fp = string.Format("{0}\\stim{1}_{2}.bmp", RetrivalDir, s, j);
                    int x = 40 + (j % 10) * 60;
                    int y = 40 + (s - 1) * 350 + (j / 10) * 60;
                    UltraPictureBox pb = new UltraPictureBox();
                    pb.Image = Image.FromFile(fp);
                    pb.Name = string.Format("pictureBox{0}_{1}", s, j);
                    pb.Size = new Size(50, 50);
                    pb.TabStop = false;
                    pb.Location = new Point(x, y);
                    pb.Cursor = Cursors.Hand;
                    pb.BorderShadowColor = Color.Yellow;
                    pb.BorderShadowDepth = ((byte)(10));
                    pb.Click += new EventHandler(pb_Click);
                    rd.imageList.Add(pb);
                }
            }
        }

        void pb_Click(object sender, EventArgs e)
        {
            ((UltraPictureBox)sender).DrawBorderShadow = !((UltraPictureBox)sender).DrawBorderShadow;
            string name = ((UltraPictureBox)sender).Name;
            int stimNo = int.Parse(name.Remove(0, 10).Split('_')[0]);
            if (((UltraPictureBox)sender).DrawBorderShadow)
            {
                _retrivalDataList[stimNo - 1].RetrivalException++;
            }
            else
            {
                _retrivalDataList[stimNo - 1].RetrivalException--;
            }
        }

        private void ultraButtonOK_Click(object sender, EventArgs e)
        {
            //  写异常文件
            string exceptionFileName = ProjectDir + @"\" + "RetrivalResult.msc";
            using (StreamWriter sw = new StreamWriter(exceptionFileName, false, Encoding.Default))
            {
                foreach (RetrivalData rd in _retrivalDataList)
                {
                    if (rd.RetrivalException > 0)
                        sw.WriteLine(rd.StimNo);
                }
            }

            //  
            this.Close();
        }

        /// <summary>
        /// 计算一些内部需要的数值
        /// </summary>
        private void CalculateData()
        {
            _millionSecondPerFrame = (int)(1000 / _videoFrameRate);
        }

        /// <summary>
        /// 读取视频文件信息
        /// </summary>
        private void ReadVideoInfo()
        {
            AviManager aviManager = new AviManager(MonitorFile, true);
            VideoStream stream = aviManager.GetVideoStream();

            _videoFrameCount = stream.CountFrames;
            _videoFrameRate = stream.FrameRate;

            aviManager.Close();
        }
    }

    public class RetrivalData
    {
        //  展现用数据
        public int StimNo = 0;                      //  刺激编号
        public int TestCaseTimeSpot = 0;            //  原始测试数据中的刺激时间点
        public int VideoFileFrameNo = 0;            //  原始测试数据中的刺激时间点对应在视频文件中的帧的编号

        //
        public Label LabelNo = new Label();
        public List<UltraPictureBox> imageList = new List<UltraPictureBox>();    //  当前刺激下的图像序列
        public List<Button> buttonList = new List<Button>();           //  图像序列对应的按钮

        //  状态数据
        public int RetrivalException = 0;           //  该刺激中有多少异常数据, 0代表没有
    }
}
